//
// Created by fairy on 2025/4/26 00:43.
//
#ifndef ZQ_I2C_H
#define ZQ_I2C_H
#include <zq_conf.h>

namespace zq
{
    namespace i2c
    {
        namespace detail
        {
            // I2C寄存器声明
            DECLARE_MMR_REGISTER(OAR, 0x3C00) // [9:0] I²C自有地址寄存器
            DECLARE_MMR_REGISTER(IER, 0x3C01) // I²C中断使能寄存器

            // 状态寄存器 (I2CSTR) 位域声明（复位值含特殊位）
            BEGIN_MMR_REGISTER(STR, 0x3C02) // 与头文件里的分布有很大出入
                // [15-10] 保留
                DECLARE_MMR_BIT(BB, 9)      // [9]  总线忙标志 (只读) 0=空闲,1=忙
                DECLARE_MMR_BIT(RSFULL, 8)  // [8]  接收移位寄存器满 (只读) 0=未满,1=满
                DECLARE_MMR_BIT(XSMT, 7)    // [7]  发送移位寄存器空 (只读) 0=未空,1=空
                DECLARE_MMR_BIT(AAS, 6)     // [6]  从地址识别 (只读) 0=未识别,1=地址匹配
                DECLARE_MMR_BIT(AD0, 5)     // [5]  地址0状态 (只读) 0=不匹配,1=匹配
                DECLARE_MMR_BIT(XRDY, 4)    // [4]  发送就绪 (只读) 0=未就绪,1=可写DXR
                DECLARE_MMR_BIT(RRDY, 3)    // [3]  接收就绪 (只读) 0=无数据,1=可读DRR
                DECLARE_MMR_BIT(ARDY, 2)    // [2]  寄存器访问就绪 (只读) 0=忙,1=配置完成
                DECLARE_MMR_BIT(NACK, 1)    // [1]  无应答标志 (写清零) 0=正常,1=检测NACK
                DECLARE_MMR_BIT(AL, 0)      // [0]  仲裁丢失标志 (写清零) 0=正常,1=丢失仲裁
            END_MMR_REGISTER()

            DECLARE_MMR_REGISTER(CLKL, 0x3C03) // I²C分频寄存器低位
            DECLARE_MMR_REGISTER(CLKH, 0x3C04) // I²C分频寄存器高位
            DECLARE_MMR_REGISTER(CNT, 0x3C05) // I²C数据计数寄存器
            DECLARE_MMR_REGISTER(DR, 0x3C06) // I²C数据接收寄存器[7:0] 原名为DRR
            DECLARE_MMR_REGISTER(SA, 0x3C07) // [9:0] I²C从机地址寄存器（复位值0x03FF） 原名为SAR
            DECLARE_MMR_REGISTER(DX, 0x3C08) // I²C数据发送寄存器[7:0] 原名为DXR


            // I2C Mode Register (I2CMDR) 位域声明
            BEGIN_MMR_REGISTER(MD, 0x3C09) // I²C模式寄存器[14:0] 原名为MDR
                DECLARE_MMR_BIT(FREE, 14) // [14] 自由运行模式 (0=禁用,1=自动重复发送)
                DECLARE_MMR_BIT(STT, 13) // [13] START条件生成 (0=无操作,1=产生START)
                DECLARE_MMR_BIT(IDLEEN, 12) // [12] 空闲模式使能 (0=禁用,1=空闲时暂停)
                DECLARE_MMR_BIT(STP, 11) // [11] STOP条件生成 (0=无操作,1=产生STOP)
                DECLARE_MMR_BIT(MST, 10) // [10] 主从模式选择 (0=从机,1=主机)
                DECLARE_MMR_BIT(TRX, 9) // [9] 传输方向 (0=接收模式,1=发送模式)
                DECLARE_MMR_BIT(XA, 8) // [8]  地址扩展 (0=7位地址,1=10位地址)
                DECLARE_MMR_BIT(RM, 7) // [7]  重复模式 (0=禁用,1=自动ACK生成)
                DECLARE_MMR_BIT(DLB, 6) // [6]  数字环回 (0=正常模式,1=内部环回)
                DECLARE_MMR_BIT(IRS, 5) // [5]  模块复位 (0=复位,1=使能模块)
                DECLARE_MMR_BIT(STB, 4) // [4]  起始字节模式 (0=禁用,1=起始字节传输)
                DECLARE_MMR_BIT(FDF, 3) // [3]  全双工模式 (0=半双工,1=全双工)
                DECLARE_MMR_BIT(BC, 0) // [2:0] 字节计数器 (4位,设置传输字节数)
            END_MMR_REGISTER()

            DECLARE_MMR_REGISTER(ISRC, 0x3C0A); // I²C中断源寄存器
            DECLARE_MMR_REGISTER(PSC, 0x3C0C); // I²C预分频寄存器
            DECLARE_MMR_REGISTER(MDR2, 0x3C0F); // I²C扩展模式寄存器
        }

        // 初始化配置结构体
        struct Config
        {
            uint32_t system_clock; // 系统时钟频率(Hz)
            uint32_t bitrate; // 目标比特率
            uint16_t own_address; // 自身地址(从机模式使用)
            bool loopback; // 环回模式使能
        };
    }

    class I2C
    {
    public:
        static void init(const i2c::Config &cfg)
        {
            using namespace i2c::detail;

            //置I2C控制器复位
            MD::IRS::clear();

            // 模块时钟 = 系统时钟 / (PSC + 1)
            // SCL周期 = (CLKL + CLKH) / 模块时钟
            // 目标：SCL频率 = 400KHz

            // 步骤1：计算预分频器PSC（生成约8-12MHz模块时钟）
            const uint32_t module_clock = 12000000; // 目标模块时钟12MHz
            const uint16_t psc = cfg.system_clock / module_clock - 1;
            PSC::write(psc);

            // 步骤2：计算CLKL/CLKH（400KHz SCL）
            const uint16_t total_cycles = module_clock / cfg.bitrate-10; // 30 cycles @12MHz
            const uint16_t clk_l = total_cycles / 2;   // 低电平周期 = 10（+6）
            const uint16_t clk_h = total_cycles - clk_l; // 高电平周期 = 10（+4）
            CLKL::write(clk_l);
            CLKH::write(clk_h);

            //设置主和从地址
            OAR::write(0x7F);

            //将I2C控制器从复位中取出，置于主模式
            MD::or_mask(MD::IRS::MASK|MD::MST::MASK);
        }


        static void send(const uint16_t device, const uint16_t reg_addr, const uint16_t data)
        {
            using namespace i2c::detail;
            // 可以使用寄存器位域里的MASK，比如MD::STP::MASK
            // 1. 配置数据计数 (2字节: 寄存器地址 + 数据)
            CNT::write(2);

            // 2. 设置从机地址 (7位模式)
            SA::write(device & 0x7F);

            // 3. 配置模式寄存器:
            MD::or_mask(
                MD::STT::MASK | //   - 产生START条件 (STT)
                MD::STP::MASK | //   - 产生STOP条件 (STP)
                MD::MST::MASK | //   - 主机模式 (MST)
                MD::TRX::MASK   //   - 发送模式 (TRX)
                // MD::IRS::MASK   //   - 启用模块 (IRS)
            );
            // 4. 发送寄存器地址 (等待发送就绪)
            DX::write(reg_addr & 0xFF);
            while (STR::XRDY::read_bit_not()) {}// 等待 XRDY (ICSTR_ICXRDY)

            // 5. 发送数据 (等待发送就绪)
            DX::write(data & 0xFF);
            while (STR::XRDY::read_bit_not()) {}// 等待 XRDY
        }


        static void disable()
        {
            //置I2C控制器复位
            i2c::detail::MD::IRS::clear();
        }
    };
}
#endif //ZQ_I2C_H
